#include<pthread.h>
#include<vector>
#include<sstream>
#include<unordered_map>
#include<fstream>
#include"Socket.hpp"


class HttpServer;
const string wwwroot="./wwwroot";//根目录
const int defaultport=8888;
const string seq="\r\n";
const string homepage="index.html";
class ThreadData
{
public:
    ThreadData(int fd,HttpServer*s)
    :sockfd(fd),svr(s)
    {}
public:
    int sockfd;
    HttpServer*svr;

};
// GET / HTTP/1.1
// host: 1.94.207.248:8888
// accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/heif,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
// upgrade-insecure-requests: 1
// user-agent: com.ss.android.ugc.aweme/230301 (Linux; U; Android 12; zh_CN; V1986A; Build/SP1A.210812.003; Cronet/TTNetVersion:d93c50bd 2022-10-17 QuicVersion:22f74f01 2022-10-11)
// accept-encoding: gzip, deflate
// Connection: Keep-Alive
//
//正文

class Httprequest
{
public:
   //反序列化传来的信息
    void Deserialize(string req){
        while(true){
            size_t pos=req.find(seq);
            if(pos==string::npos) break;
            string temp=req.substr(0,pos);
            if(temp.empty())break;
            req_header.push_back(temp);
            req.erase(0,pos+seq.size());
        }
        text=req;
    }
    void Parse(){
        std::stringstream ss(req_header[0]);//分割字符串以空格为单位
        ss>>method>>url>>http_version;

        file_path=wwwroot;//文件路径
        if(url=="/"||url=="/index.html")
        {
            file_path+="/";
            file_path+=homepage;
        }
        else file_path+=url;

        auto pos=file_path.rfind(".");
        if(pos==string::npos){
           suffix=".html";
        }
        else{
             suffix=file_path.substr(pos);
        }
    }
    void DebugPrint()
    {
        for(auto &line : req_header)
        {
            std::cout << "--------------------------------" << std::endl;
            std::cout << line << "\n\n";
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }
public:
    string text;//正文
    vector<string>req_header;//报头信息
    string method;//方式
    string url;//目录
    string http_version;//http版本号
    string file_path;//根目录
    string suffix;//访问的是什么文件
};

class HttpServer
{
public:
    HttpServer(uint16_t port=defaultport)
    :port_(port)
    {
        content_type.insert({".html","text/html"});
    }
    void start(){
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        for(;;){
            string clientip;
            uint16_t clientport;
            long long int sockfd=listensock_.Accept(&clientip,&clientport);
            if(sockfd<0)continue;
            lg(Info,"get a new connect,sockfd:%d",sockfd);
            pthread_t tid;
            ThreadData*td=new ThreadData(sockfd,this);
            pthread_create(&tid,nullptr,ThreadRun,td);
        }
    }
    static string ReadHtmlContent(const string &htmlpath){//读取文件路径的内容
        ifstream in(htmlpath,std::ios::binary);//文件流
        if (!in.is_open()) {  
            //cerr << "Error opening file: " << htmlpath << endl;  // 输出错误信息  
             return "";  
      }  
        in.seekg(0,std::ios_base::end);//设定读取指针的位置到文件末尾
        auto len=in.tellg();//读取指针的位置，也就是文件有多大
        in.seekg(0,std::ios_base::beg);//设定读取指针的位置到开头

        string content;//读取文章的内容开的空间
        content.resize(len);

        in.read((char*)content.c_str(),content.size());
        in.close();
        return content; 
    }
    string SuffixToDesc(const std::string &suffix)
    {
        auto iter=content_type.find(suffix);
        if(iter==content_type.end())return content_type[".html"];
        else return content_type[suffix];
    }
   void HandlerHttp(int sockfd){
        char buffer[10240];
        ssize_t n=recv(sockfd,buffer,sizeof(buffer)-1,0);
        if(n>0){
            buffer[n]=0;
            std::cout<<buffer<<std::endl;
            Httprequest req;
            req.Deserialize(buffer);
            req.Parse();
           // req.DebugPrint();
            string text;
            bool ok=true;
            text=ReadHtmlContent(req.file_path);//返回要访问页面的代码
            if(text.empty())
            {
                ok=false;//要读取的文件失败
            }
            string response_line;//返回
            if(ok)
                response_line="HTTP/1.0 200 OK\r\n";
            else
                response_line="HTTP/1.0 404 Not Found\r\n";
            string response_header="Content-Length:";
            response_header+=to_string(text.size());
            response_header+="\r\n";
            response_header+="Content-Type:";
            response_header+=SuffixToDesc(req.suffix);
            response_header+="\r\n";
            // response_header+="Set-Cookie: name=haha&&passwd=1234";
            // response_header+="\r\n";
            std::string blank_line = "\r\n"; 

            string response=response_line;
            response+=response_header;
            response+=blank_line;
            response+=text;
            send(sockfd,response.c_str(),response.size(),0);
        }
        close(sockfd);
    }

    static void* ThreadRun(void *args){
        ThreadData*td=static_cast<ThreadData*>(args);
        pthread_detach(pthread_self());//线程分离
        td->svr->HandlerHttp(td->sockfd);
        return nullptr;
    }
    ~HttpServer()
    {}

private:
    Sock listensock_;
    uint16_t port_;
    std::unordered_map<std::string, std::string> content_type;//文件类型

};